#! /usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import time
import struct
import os.path as osp
import xml.etree.ElementTree as ET

from plate_syndata import *
from db_conf import *
import global_var 

SDF_HEADER_SIZE = 0x7CF
MAIN_COLL_NAME = "flattensys"
SHAPELINE_DATA = "shape_detail"

log = global_var.gl_log


def traverseXml(element, data_map):
    #print (len(element))
    if len(element)>0:
        for child in element:
            #print (child.tag, "----", child.attrib["name"], "=", child.text)
            # if child.tag=="float" and (child.attrib["name"] in SHAPE_DATA_ITEM):
            if  child.attrib["name"] in SHAPE_DATA_ITEM:
                if child.tag == "float":
                    data_map[child.attrib["name"]]=float(child.text)
                elif child.tag=="wxString":
                    data_map[child.attrib["name"]]=child.text

            data_map = traverseXml(child, data_map)
    return data_map

def read_xml_data(root,data_type=["float"]):
    data_map = {}
    if root==None:
        return data_map
 
    data_map = traverseXml(root, data_map)
    return data_map

class SDFReader(object):
    def __init__(self):
        pass

    def read_shape(self, filepath):
        list_col_data = []
        print("read shape: {}".format(filepath))
        with open(filepath, 'rb') as f:
            # drop header
            self.Header = f.read(SDF_HEADER_SIZE)
            # print("step 1 read to %x" % len(self.Header))
            operationGraph_size = int.from_bytes(f.read(4), byteorder='little')
            operationGraph_bytes = f.read(operationGraph_size * 2)
            # print("step 2 read to %x" % (len(operationGraph_bytes)+len(self.Header)))
            self.OperationGraph = str(operationGraph_bytes, encoding='utf-16-le')
            
            # handle rest data: data block + folder xml
            data = f.read()#read the left data
            # idx_stx = len(operationGraph_bytes)+len(self.Header)
            # print("step 3 read last %x" % (idx_stx+len(data)))
            #print("date len = ", len(data))
            idx_end = len(data)
            for i in range(len(data) - 8):
                # search: '<?xml'
                if data[i] == 0x3C and data[i + 2] == 0x3F and data[i + 4] == 0x78 and data[i + 6] == 0x6D and data[i + 8] == 0x6C:
                    idx_end = i
                    break

            if idx_end:
                # f_out = open("data.txt","a+")
                # print("data end = %x" % (idx_end+idx_stx))
                
                row_num = 0
                for i in range(idx_end):
                    if data[i] == 0x6f and data[i+1] == 0x00 and data[i+2]==0 and data[i+3]==0:
                        list_row_data = [] #
                        #3 int: all col number, data start, act col number 
                        all_count = int.from_bytes(data[i : i + 4], byteorder='little')
                        dat_start = int.from_bytes(data[i + 4: i + 8], byteorder='little')
                        col_count = int.from_bytes(data[i + 8: i + 12], byteorder='little') 
                        

                        #i_stx = i + 12
                        i = i + 12
                        for j in range(0, dat_start):
                            list_row_data.append(-100.0)
                        for j in range(0, col_count):
                            #_v = struct.unpack('<f', data[i_stx+j*8+4:i_stx+j*8+8])[0]
                            _v = struct.unpack('<f', data[i+j*8+4:i+j*8+8])[0]                            
                            list_row_data.append(_v)
                        for j in range(0, all_count-dat_start-col_count):
                            list_row_data.append(-100.0)
                        i = i + col_count*8
                        #for j in range(col_count):_v = struct.unpack('<f', data[i+j*8+4:i+j*8+8])[0]
                        if len(list_row_data):
                            list_col_data.append(list_row_data)
                            # f_out.write("%04d,"%(row_num))

                        # for item in list_row_data:
                        #     f_out.write("%.2f, " % (item))
                        # f_out.write("\n")

                        row_num += 1
        return list_col_data[:-1] 

    def read_folder(self, filepath):
        with open(filepath, 'rb') as f:
            # drop header
            self.Header = f.read(SDF_HEADER_SIZE)
            operationGraph_size = int.from_bytes(f.read(4), byteorder='little')
            operationGraph_bytes = f.read(operationGraph_size * 2)
            self.OperationGraph = str(operationGraph_bytes, encoding='utf-16-le')
            
            # handle rest data: data block + folder xml
            data = f.read()
            for i in range(len(data) - 8):
                # search: '<?xml'
                if data[i] == 0x3C and data[i + 2] == 0x3F and data[i + 4] == 0x78 and data[i + 6] == 0x6D and data[i + 8] == 0x6C:
                    # check xml size
                    size = int.from_bytes(data[i - 4 : i], byteorder='little') * 2
                    # print("size+4 = ",size+4)
                    # print("len(data)-i", len(data)-i)

                    #assert size + 4 == len(data) - i, '"Folder" xml size check error'



                    self.Folder = str(data[i : i+size], encoding='utf-16-le')
                    self.DataBlock = data[: i - 4]
                    return
            raise Exception('Can not find "Folder" xml tag')


class CShapeData:
    def __init__(self, db_proc=None, file_name=""):
        self.shape_file = file_name
        self.db_proc = db_proc
    
    def read_xml(self, root, data_type=["float"]):
        data_map = {}
        if root==None:
            return data_map
    
        data_map = traverseXml(root, data_map)
        return data_map
        
    #[file_name]: full path name
    def extract_data(self, file_name,pid):
        # self.shape_file = file_name
        # db_proc.update(MAIN_COLL_NAME, plate_oid, )
        try:
            sdf = SDFReader()#(file_name)
            #print("0 ------- ")
            sdf.read_folder(file_name)
            #print("1-------")
            data_shp = sdf.read_shape(file_name)
            #print("1-1------")
            #log.info("1------")
            root = ET.fromstring(sdf.Folder)
            #log.info("2------")
            shapedata = self.read_xml(root)
            #log.info("3------")
            synpd = CPlateDataSyn()
            oid = synpd.get_oid(pid)
            # plate_id = file_name.split("_")[0]
            # plate_id = plate_id.split("/")[-1]

            #log.info("extract data for {}({})".format(pid,oid))
            print("shape_data: \n", shapedata)
            if self.db_proc and oid:
                self.db_proc.update(MAIN_COLL_NAME, oid, shapedata)
            #inert shape data 
                self.db_proc.insert(SHAPELINE_DATA,{"_id":oid,"plate_id":pid,"data":data_shp,"filename":file_name})
                
        except Exception as e:

            #log.error("extra shape data err: {}".format( e))
            print("extra shape data err: {}".format( e))


def run_test(filename = "./download/2019-12-31 16.25.35 -112903878503        .sdf"):
    shp = CShapeData()
    shp.extract_data(filename,"0")

if __name__=="__main__":
    run_test(sys.argv[1])
            
